package com.awenhui.demo.core.utils.zutils.convert;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.awenhui.demo.core.utils.zutils.KtwlDateUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.PostConstruct;
import javax.validation.constraints.NotNull;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 类型转换工具类
 *
 * @author zhouxuanhong
 * @date 2019-04-01 16:51
 * @since JDK1.8
 */
@Component
@Slf4j
public class ConvertUtil {
    private static ConvertUtil util;
    private ModelMapper modelMapper;

    @Autowired
    public ConvertUtil(ModelMapper modelMapper) {
        this.modelMapper = modelMapper;
    }

    /**
     * 对象拷贝-同时实现Map to Map(创建目标对象并拷贝数据)
     *
     * @param source     ${@link Object} 原对象
     * @param targetType ${@link Class}  目标对象类型类
     * @author zhouxuanhong
     * @date 2019-04-10 19:03
     */
    public static <T> T map(Object source, Class<T> targetType) {
        if (!(source instanceof Map)) {
            try {
                T t = targetType.getDeclaredConstructor().newInstance();
                if (t instanceof Map) {
                    objToMap(source, t);
                    return t;
                }
            } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
                e.printStackTrace();
            }
        }
        return util.modelMapper.map(source, targetType);
    }

    /**
     * 对象拷贝-同时实现Map to Map(拷贝数据,不创建目标对象)
     *
     * @param source ${@link Object} 原对象
     * @param target ${@link Object}  目标对象
     * @author zhouxuanhong
     * @date 2019-04-29 15:24
     */
    public static void map(Object source, Object target) {
        if (!(source instanceof Map) && target instanceof Map) {
            objToMap(source, target);
        } else {
            util.modelMapper.map(source, target);
        }
    }

    /**
     * list集合拷贝
     *
     * @param source
     * @param target
     */
    public static <T> T map(Object source, Type target) {
        return util.modelMapper.map(source, target);
    }

    /**
     * 对象拷贝-同时实现Map to Map(创建目标对象并拷贝数据,同时处理字段适配,字段适配需要添加FieldAdapt注解在实体上说明适配策略)
     *
     * @param source     ${@link Object} 原对象
     * @param targetType ${@link Class}  目标对象类型类
     * @author zhouxuanhong
     * @date 2019-04-10 19:03
     */
    public static <T> T mapAndAdapt(Object source, Class<T> targetType) {
        JSONObject jsonObject = toJSONObject(source);
        try {
            T t = targetType.getDeclaredConstructor().newInstance();
            // 处理字段适配
            Field[] fields = targetType.getDeclaredFields();
            for (Field field : fields) {
                FieldAdapt fieldAdapt = field.getAnnotation(FieldAdapt.class);
                if (fieldAdapt == null) {
                    continue;
                }
                field.setAccessible(true);
                // 获取目标值
                String key = fieldAdapt.source();
                Object obj = jsonObject.get(key);
                if (obj != null && StringUtils.isNotBlank(key)) {
                    // 处理日期
                    obj = dealWithDate(fieldAdapt, obj);
                    // 处理字段适配
                    obj = dealWithFieldAdapt(fieldAdapt, obj, jsonObject, key, field);
                }
                // 移除已经处理过的字段，避免对象拷贝时因类型不匹配抛出异常
                jsonObject.remove(key);
                if (obj != null && StringUtils.isNotBlank(obj.toString())) {
                    field.set(t, obj);
                }
            }
            // 处理其余字段数据拷贝
            util.modelMapper.map(jsonObject, t);
            return t;
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 实体或map参数拼接为get请求的地址参数
     *
     * @param source ${@link Object} 原对象
     * @return String ${@link String} get请求的参数字符串
     * @author zhouxuanhong
     * @date 2019-04-24 12:32
     */
    public static String toGetParams(Object source) {
        StringBuilder sb = new StringBuilder();
        // 处理map
        JSONObject jsonObject = map(source, JSONObject.class);
        boolean flag = false;
        for (String key : jsonObject.keySet()) {
            Object value = jsonObject.get(key);
            if (!flag) {
                flag = true;
                sb.append(key).append("=").append(value);
            } else {
                sb.append("&").append(key).append("=").append(value);
            }
        }
        return sb.toString();
    }

    /**
     * json 字符串转为Java Bean
     *
     * @param jsonString ${@link String}
     * @param target     ${@link Class}
     * @author zhouxuanhong
     * @date 2019-05-15 10:57
     */
    public static <T> T jsonStringToBean(Object jsonString, Class<T> target) {
        String str;
        if (jsonString instanceof String) {
            str = jsonString.toString();
        } else {
            str = JSONObject.toJSONString(jsonString);
        }
        return JSONObject.parseObject(str, target);
    }

    /**
     * Object 转为JSONObject
     *
     * @param source ${@link Object}  原数据
     * @return JSONObject ${@link JSONObject}
     * @author zhouxuanhong
     * @date 2019-05-10 22:53
     */
    public static JSONObject toJSONObject(Object source) {
        String jsonString = JSONObject.toJSONString(source);
        return JSON.parseObject(jsonString);
    }

    /**
     * 实体转map
     *
     * @param source ${@link Object} 原对象
     * @param target ${@link Object} 目标map
     * @author zhouxuanhong
     * @date 2019-04-03 14:08
     */
    private static void objToMap(Object source, Object target) {
        if (source == null) {
            return;
        }
        if (target instanceof Map) {
            Map<Object, Object> map = (Map<Object, Object>) target;
            Field[] fields = source.getClass().getDeclaredFields();
            for (Field field : fields) {
                try {
                    Field f = source.getClass().getDeclaredField(field.getName());
                    f.setAccessible(true);
                    Object o = f.get(source);
                    map.put(field.getName(), o);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 字符串转8大基本类型
     *
     * @param typeName ${@link String} 类型名称
     * @param value    ${@link String} 待转换字符串
     * @return Object ${@link Object}
     * @author zhouxuanhong
     * @date 2019-04-30 17:20
     */
    private static Object typeFormat(String typeName, String value) {
        Object obj = null;
        if (StringUtils.isNotBlank(value)) {
            switch (typeName) {
                case "Integer":
                    obj = Integer.parseInt(value);
                    break;
                case "Boolean":
                    obj = Boolean.parseBoolean(value);
                    break;
                case "Long":
                    obj = Long.parseLong(value);
                    break;
                case "Byte":
                    obj = Byte.parseByte(value);
                    break;
                case "Short":
                    obj = Short.parseShort(value);
                    break;
                case "Double":
                    obj = Double.parseDouble(value);
                    break;
                case "Float":
                    obj = Float.parseFloat(value);
                    break;
                default:
                    obj = value;
            }
        }
        return obj;
    }

    /**
     * 处理日期
     *
     * @param fieldAdapt ${@link FieldAdapt} 注解
     * @param obj        ${@link Object} 目标数据
     * @return Object ${@link Object} 返回处理后的数据
     * @author zhouxuanhong
     * @date 2019-04-30 17:27
     */
    private static Object dealWithDate(FieldAdapt fieldAdapt, Object obj) {
        // 处理字符串转日期
        String format = fieldAdapt.toDateFormat();
        if (StringUtils.isNotBlank(format)) {
            obj = KtwlDateUtils.formatDate(obj.toString(), format);
        }
        // 处理日期转字符串
        format = fieldAdapt.toStringFormat();
        if (StringUtils.isNotBlank(format)) {
            obj = KtwlDateUtils.getStringDate(format, (Date) obj);
        }
        // 处理字符串转时间戳
        format = fieldAdapt.toLongFormat();
        if (StringUtils.isNotBlank(format)) {
            obj = KtwlDateUtils.formatLong(obj.toString(), format);
        }
        return obj;
    }

    /**
     * 处理字段适配
     *
     * @param fieldAdapt ${@link FieldAdapt} 注解
     * @param obj        ${@link Object} 目标数据
     * @param source     ${@link JSONObject} 原数据
     * @param key        ${@link String} 注解需要适配原数据属性名称
     * @param field      ${@link Field} 属性
     * @return Object ${@link Object} 返回处理后的数据
     * @author zhouxuanhong
     * @date 2019-04-30 17:28
     */
    private static Object dealWithFieldAdapt(FieldAdapt fieldAdapt, Object obj, JSONObject source, String key, Field field) {
        String adapt = fieldAdapt.adapt();
        if (StringUtils.isNotBlank(adapt)) {
            String sourceValue = source.getString(key);
            String[] mappings = adapt.split(",");
            for (String mapping : mappings) {
                if (mapping.contains(sourceValue)) {
                    String value = mapping.substring(mapping.indexOf("-") + 1);
                    // 处理类型转换
                    String typeName = field.getType().getSimpleName();
                    obj = typeFormat(typeName, value);
                }
            }
        }
        return obj;
    }


    /**
     * 一个List<A>转另一个List<B>
     *
     * @param sources    ${@link List<Object>}
     * @param targetType ${@link Class<T>}
     * @return List<T> ${@link List<T>}
     * @author zhouxuanhong
     * @date 2019-09-11 10:51
     */
    public static <T> List<T> listAToListBByModelMapper(@NotNull List<?> sources, @NotNull Class<T> targetType) {
        List<T> target = new ArrayList<>();
        if (!CollectionUtils.isEmpty(sources) && targetType != null) {
            sources.forEach(v -> {
                T t = ConvertUtil.map(v, targetType);
                target.add(t);
            });
        }
        return target;
    }


    /**
     * 一个List<A>转另一个List<B>
     *
     * @param sources    ${@link List<Object>}
     * @param targetType ${@link Class<T>}
     * @return List<T> ${@link List<T>}
     * @author zhouxuanhong
     * @date 2019-09-11 10:51
     */
    public static <T> List<T> listAToListBByJson(@NotNull List<?> sources, @NotNull Class<T> targetType) {
        if (!CollectionUtils.isEmpty(sources) && targetType != null) {
            String jsonString = JSONObject.toJSONString(sources);
            return JSONObject.parseArray(jsonString, targetType);
        }
        return new ArrayList<>();
    }

    /**
     * 初始化
     *
     * @author zhouxuanhong
     * @date 2019-04-29 15:34
     */
    @PostConstruct
    private void init() {
        util = this;
    }
}

